import { Component, OnInit, OnDestroy, ViewChild, TemplateRef } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { Subscription, of, zip, Observable, throwError } from 'rxjs'
import { switchMap, concatMap, tap, take } from 'rxjs/operators'
import { NzMessageService } from 'ng-zorro-antd'

import { DetailTabClass } from '@shared/classes/DetailTabClass'
import { Store, StoreRiskControlUpdate, StoreFull } from '@shared/interfaces/store'
import { DataService } from '@shared/services/data.service'
import { StoreService } from '../../store.service'
import { PageService } from '@shared/services/page.service'
import { ETabScrollStatus, ECustomAcl } from '@shared/enums'
import { IBaseInfoColumn } from '@shared/interfaces/baseInfo'
import { RiskControlScheme, Institution } from '@shared/interfaces/risk-control'
import { I18NService } from '@core'
import { AcquirerService } from 'app/routes/acquirer/acquirer.service'
import { CustomACLService } from '@shared/services/acl.service'

@Component({
  selector: 'app-store-tab-risk-control',
  templateUrl: './tab-risk-control.component.html',
})
export class StoreDetailTabRiskControlComponent extends DetailTabClass<RiskControlScheme> implements OnInit, OnDestroy {
  constructor(
    private dataService: DataService,
    private storeService: StoreService,
    private i18n: I18NService,
    private acquirerService: AcquirerService,
    private msg: NzMessageService,
    public pageService: PageService,
    public route: ActivatedRoute,
    private customACLService: CustomACLService,
  ) {
    super(pageService, route)
  }

  private subscription: Subscription
  private store: Store

  isSupportRisk = false
  isSupportPostRisk = false
  riskScheme: RiskControlScheme
  postRiskScheme: RiskControlScheme
  insCode: string | Institution

  @ViewChild('operate') operate: TemplateRef<any>
  @ViewChild('operateOfPostRC') operateOfPostRC: TemplateRef<any>
  @ViewChild('tpRCSelect') tpRCSelect: TemplateRef<any>
  @ViewChild('tpPostRCSelect') tpPostRCSelect: TemplateRef<any>

  fields = {
    RiskControl: '0', // 事中风控
    PostRiskControl: '1', // 事后风控
  }

  get isNeedDiff(): boolean {
    return this.dataService.isNeedDiff
  }

  ngOnInit() {
    this.initialColumns()
    this.initAclAbility()
    this.initSubscription()
    this.initialData()
  }

  ngOnDestroy(): void {
    this.subscription.unsubscribe()
    this.customACLService.removeACLAbility(ECustomAcl.StoreEditable)
    this.customACLService.removeACLAbility(ECustomAcl.AcquirerSupportDualMessage)
  }

  initAclAbility(): void {
    this.customACLService.addACLAbility(ECustomAcl.StoreEditable)
    this.customACLService.addACLAbility(ECustomAcl.AcquirerSupportDualMessage)
  }

  initSubscription(): void {
    this.pageService.isStoreDisplayInTask$
      .pipe(
        tap(isStoreDisplayInTask => {
          if (isStoreDisplayInTask) {
            this.customACLService.removeACLAbility(ECustomAcl.StoreEditable)
          }
        }),
        switchMap(() => this.pageService.isStoreLocked$),
        tap(isStoreLocked => {
          if (isStoreLocked) {
            this.customACLService.removeACLAbility(ECustomAcl.StoreEditable)
          }
        }),
      )
      .subscribe()
  }

  initialData() {
    const { origStore, currentStore } = this.dataService
    if (this.isNeedDiff) this.origData = origStore.common.riskControl
    this.subscription = this.dataService.storeFull$.value$.subscribe(storeFull => {
      this.initDisplay(storeFull)
      this.setEdit(this.fields.RiskControl, 1)
      this.setupIdForColumn(this.fields)
    })
    this.pageService.setTabScrollStatus(ETabScrollStatus.Scroll)
  }

  initDisplay(storeFull: StoreFull): void {
    const { store } = storeFull
    this.store = store
    this.acquirerService
      .getOne(store.common.insCode)
      .pipe(
        concatMap(acq => {
          if (!acq.institution.common.feature) {
            throwError('acq.institution.common.feature is undefined')
          }

          const { isSupportRisk, isSupportPostRisk } = acq.institution.common.feature
          if (!isSupportRisk && !isSupportPostRisk) {
            throwError('this acquirer doesn\'t support risk control')
          }

          this.isSupportRisk = isSupportRisk
          this.isSupportPostRisk = isSupportPostRisk

          let rc: RiskControlScheme
          let postRC: RiskControlScheme
          if (isSupportRisk) {
            rc = storeFull.riskScheme
          }
          if (isSupportPostRisk) {
            postRC = storeFull.postRiskScheme
            this.insCode = postRC.insCode || storeFull.store.common.insCode
          }

          return of([rc, postRC])
        }),
        tap(input => {
          const [rc, postRC] = input
          this.postRiskScheme = postRC
          this.createColumns(rc, postRC)
        }),
        take(1),
      )
      .subscribe()
  }

  changPostRisk(postRiskScheme: RiskControlScheme) {
    this.subscription = this.dataService.storeFull$.value$.subscribe(storeFull => {
      storeFull.postRiskScheme = postRiskScheme
      this.createPostRCColumns(storeFull.postRiskScheme)
        .pipe(take(1))
        .subscribe(col => {
          this.columns[this.fields.PostRiskControl] = [col]
        })
    })
  }

  private createColumns(rc: RiskControlScheme, postRC: RiskControlScheme): void {
    this.createRCColumns(rc)
      .pipe(take(1))
      .subscribe(col => {
        this.setEdit(this.fields.RiskControl, !!rc ? Object.keys(rc).length : 0)
        this.columns[this.fields.RiskControl] = [col]
      })

    this.createPostRCColumns(postRC)
      .pipe(take(1))
      .subscribe(col => {
        this.setEdit(this.fields.PostRiskControl, !!postRC ? Object.keys(postRC).length : 0)
        this.columns[this.fields.PostRiskControl] = [col]
      })
  }

  // 创建事中风控行
  private createRCColumns(rc: RiskControlScheme = new RiskControlScheme()): Observable<IBaseInfoColumn[]> {
    return zip(this.pageService.isStoreDisplayInTask$, this.pageService.isStoreLocked$).pipe(
      switchMap(result => {
        const [isStoreDisplayInTask, isStoreLocked] = result
        const operateColumn =
          !isStoreDisplayInTask && !isStoreLocked
            ? [
                {
                  span: 4,
                  label: 'GENERAL.INFO.OPERATION',
                  labelI18n: 'GENERAL.INFO.OPERATION',
                  // template: this.operate,
                  operate: true,
                },
              ]
            : []
        // const span = !isStoreDisplayInTask && !isStoreLocked ? 20 : 24
        return of([
          {
            span: 5,
            label: '风控方案代码',
            labelI18n: 'RISK_CTRL.SCHEME_CODE',
            index: 'schemeCode',
            template: this.tpRCSelect,
            value: rc.schemeCode,
          },
          {
            span: 5,
            label: '风控方案名称',
            labelI18n: 'RISK_CTRL.SCHEME_NAME',
            index: 'schemeName',
            value: rc.schemeName,
          },
          {
            span: 5,
            label: '方案描述',
            labelI18n: 'RISK_CTRL.SCHEME_DESC',
            index: 'remark',
            value: rc.schemeName,
          },
          {
            span: 5,
            label: '风控方案类型',
            labelI18n: 'RISK_CTRL.CATEGORY',
            index: 'category',
            value: rc.schemeName,
          },
          ...operateColumn,
        ])
      }),
    )
  }

  // 创建事后风控行
  private createPostRCColumns(rc: RiskControlScheme = new RiskControlScheme()): Observable<IBaseInfoColumn[]> {
    const spanWidth = 6
    const columns: IBaseInfoColumn[] = [
      {
        span: spanWidth,
        label: '风控方案代码',
        labelI18n: 'RISK_CTRL.SCHEME_CODE',
        index: 'schemeCode',
        template: this.tpPostRCSelect,
        value: rc.schemeCode,
      },
      {
        span: spanWidth,
        label: '风控方案名称',
        labelI18n: 'RISK_CTRL.SCHEME_NAME',
        index: 'schemeName',
        disEditable: true,
        value: rc.schemeName,
      },
      {
        span: spanWidth,
        label: '方案描述',
        labelI18n: 'RISK_CTRL.SCHEME_DESC',
        index: 'schemeDesc',
        disEditable: true,
        value: rc.schemeDesc,
      },
      {
        span: spanWidth,
        label: 'OPERATION',
        labelI18n: 'GENERAL.INFO.OPERATION',
        template: this.operateOfPostRC,
        operate: true,
        acl: ['api.put.camel.store.one.risk_control', ECustomAcl.StoreEditable],
        aclMode: 'allOf',
      },
    ]
    return of(columns)
  }

  // abstract methods
  onCancel() {}

  onSubmit() {
    const d = new StoreRiskControlUpdate(this.store.version)
    if (this.riskScheme) {
      d.riskSchemeCode = this.riskScheme.schemeCode
    }
    if (this.postRiskScheme) {
      d.postRiskSchemeCode = this.postRiskScheme.schemeCode
    }
    const token = this.dataService.token

    this.storeService.updateRiskControl(this.store.common.intStoreCode, token, d).subscribe(result => {
      this.pageService.setStoreBeenModified(true)
      if (result instanceof StoreFull) {
        this.initDisplay(result)
        if (result!.store!.version) {
          this.store.version = result.store.version
        }
      } else {
        this.msg.success(this.trans('GENERAL.INFO.SUBMIT_AFTER_SAVING'))
      }

      this.isEdits[this.field][this.rowIndex] = false
    })
  }

  initialColumns() {
    /*
     * 这个columns是用来收集所有需要display在这个tab里面的数据.
     * 比如 "交易币种转换" = '1', 然后交易币种转换里有一个Array = [商户交易币种, 转换交易币种, 转换汇率, 等等] 然后他在columns里就是
     * {'1': [[{商户交易币种, 转换交易币种, 转换汇率, 等等}]]}
     */
    // 现在这个trades component需要展示2个field. 这里创建2个空的Array在this.columns里的field
    for (const key in this.fields) {
      this.columns[this.fields[key]] = []
    }
  }

  trans(key: string, params?: Object): string {
    return this.i18n.fanyi(key, params)
  }
}
